package castledefense.util;

import java.util.HashMap;
import java.util.Map;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.files.FileHandle;

/**
 * A class that stores Sounds.
 * @author Roi Atalla
 */
public class SoundManager {
	private Map<String,Sound> sounds;
	private float volume = 1;
	
	public SoundManager() {
		sounds = new HashMap<String,Sound>();
	}
	
	/**
	 * Returns the canonical name of this file path. It strips the path and the extension.
	 * @param file The file to be canonicalized.
	 * @return The canonical name of this file.
	 */
	public static String getFileName(String file) {
		file = file.replace("\\","/");
		return file.substring(file.lastIndexOf("/")+1,file.lastIndexOf("."));
	}
	
	/**
	 * This method searches the root directory for the file path. Then it opens a Sound on the specified file.
	 * Its associated name is set as its canonical name.
	 * @param file The file to import.
	 * @return The Sound.
	 */
	public Sound add(String file) {
		return add(file,getFileName(file));
	}
	
	/**
	 * This method searches the root directory for the file path. Then it opens a Sound on the specified file.
	 * @param file The file to import.
	 * @param name The name to associate with this Sound.
	 * @return The Sound.
	 */
	public Sound add(String file, String name) {
		return add(Gdx.files.internal(file),name);
	}
	
	/**
	 * Opens a Sound on this URL.
	 * @param url The URL of the sound file.
	 * @param name The name to associate with this Sound.
	 * @return The Sound.
	 */
	public Sound add(FileHandle file, String name) {
		return add(Gdx.audio.newSound(file), name);
	}
	
	/**
	 * Adds the Sound.
	 * @param Sound The Sound to add.
	 * @param name The name to associate with this Sound.
	 * @return The Sound that was added.
	 */
	public synchronized Sound add(Sound sound, String name) {
		return sounds.put(name,sound);
	}
	
	/**
	 * Returns the Sound with the specified name.
	 * @param name The name of the Sound.
	 * @return The Sound with the specified name.
	 */
	public Sound get(String name) {
		return sounds.get(name);
	}
	
	/**
	 * Renames the Sound with the specified name.
	 * @param oldName The old name.
	 * @param newName The new name.
	 * @throws Exception
	 */
	public void rename(String oldName, String newName) {
		add(remove(oldName),newName);
	}
	
	/**
	 * Replaces the Sound associated with the specified name with the specified Sound. Does the same thing as <code>add(Sound,String)</code>
	 * @param oldName The name of the old Sound.
	 * @param newSound The new Sound that will replace the old Sound.
	 * @return The Sound that was replaced.
	 */
	public Sound replace(String oldName, Sound newSound) {
		if(get(oldName) == null)
			throw new IllegalArgumentException("Invalid name");
		
		Sound Sound = get(oldName);
		add(newSound,oldName);
		return Sound;
	}
	
	/**
	 * Swaps the Sounds of both specified names.
	 * @param first The first Sound.
	 * @param second The second Sound.
	 */
	public synchronized void swap(String first, String second) {
		Sound s = sounds.get(first);
		Sound s2 = sounds.get(second);
		
		if(s == null)
			throw new IllegalArgumentException("First name is invalid.");
		if(s2 == null)
			throw new IllegalArgumentException("Second name is invalid");
		
		sounds.put(second,sounds.put(first,sounds.get(second)));
	}
	
	/**
	 * Removes the Sound.
	 * @param name The name of the Sound.
	 * @return The Sound that was removed.
	 */
	public synchronized Sound remove(String name) {
		Sound s = get(name);
		sounds.remove(name);
		return s;
	}
	
	/**
	 * Plays the Sound at the set volume.
	 * @param name The name of the Sound to play.
	 */
	public void play(String name) {
		get(name).play(volume);
	}
	
	/**
	 * Stops the specified Sound.
	 * @param name The name of the Sound to stop.
	 */
	public void stop(String name) {
		get(name).stop();		
	}
	
	public void stop() {
		for(Sound s : sounds.values())
			s.stop();
	}
	
	public void setVolume(float volume) {
		this.volume = volume;
	}
	
	public float getVolume() {
		return volume;
	}
	
	public void dispose() {
		for(Sound s : sounds.values()) {
			s.stop();
			s.dispose();
		}
		
		sounds.clear();
	}
}